<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>第10章 如何正确地进行抽象 | 深入理解Vue.js实战</title>
    <meta name="description" content="作者：被删">
    
    
    <link rel="preload" href="/vue-ebook/assets/css/0.styles.b08616b1.css" as="style"><link rel="preload" href="/vue-ebook/assets/js/app.0a4e61a5.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/3.846561a8.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/2.eed49fdd.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/9.748381e0.js" as="script">
    <link rel="stylesheet" href="/vue-ebook/assets/css/0.styles.b08616b1.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/vue-ebook/" class="home-link router-link-active"><!----> <span class="site-name">深入理解Vue.js实战</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/vue-ebook/" class="nav-link">概述</a></div><div class="nav-item"><a href="/vue-ebook/vue-ebook/" class="nav-link router-link-active">内容</a></div> <a href="https://github.com/godbasin/vue-ebook" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/vue-ebook/" class="nav-link">概述</a></div><div class="nav-item"><a href="/vue-ebook/vue-ebook/" class="nav-link router-link-active">内容</a></div> <a href="https://github.com/godbasin/vue-ebook" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>前言</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/0.html" class="sidebar-link">前端框架的出现</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>第一部分 Vue快速入门</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/1.html" class="sidebar-link">第1章 Vue 框架介绍</a></li><li><a href="/vue-ebook/vue-ebook/2.html" class="sidebar-link">第2章 Vue 环境快速搭建</a></li><li><a href="/vue-ebook/vue-ebook/3.html" class="sidebar-link">第3章 Vue 基础介绍</a></li><li><a href="/vue-ebook/vue-ebook/4.html" class="sidebar-link">第4章 Vue 组件的使用</a></li><li><a href="/vue-ebook/vue-ebook/5.html" class="sidebar-link">第5章 常用指令和自定义指令</a></li><li><a href="/vue-ebook/vue-ebook/6.html" class="sidebar-link">第6章 Vue 动画</a></li><li><a href="/vue-ebook/vue-ebook/7.html" class="sidebar-link">第7章 Vue Router 路由搭建应用</a></li><li><a href="/vue-ebook/vue-ebook/8.html" class="sidebar-link">第8章 实战：Todo List 从组件到应用</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:10px;"><div class="kitty-main" data-v-0cd75e06><span class="stand" data-v-0cd75e06></span> <div class="cat" data-v-0cd75e06><div class="body" data-v-0cd75e06></div> <div class="head" data-v-0cd75e06><div class="ear" data-v-0cd75e06></div> <div class="ear" data-v-0cd75e06></div></div> <div class="face" data-v-0cd75e06><div class="nose" data-v-0cd75e06></div> <div class="whisker-container" data-v-0cd75e06><div class="whisker" data-v-0cd75e06></div> <div class="whisker" data-v-0cd75e06></div></div> <div class="whisker-container" data-v-0cd75e06><div class="whisker" data-v-0cd75e06></div> <div class="whisker" data-v-0cd75e06></div></div></div> <div class="tail-container" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06><div class="tail" data-v-0cd75e06></div></div></div></div></div></div></div></div></div></div> <p class="sidebar-heading open"><span>第二部分 Vue的正确使用方式</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/9.html" class="sidebar-link">第9章 思维转变与大型项目管理</a></li><li><a href="/vue-ebook/vue-ebook/10.html" class="active sidebar-link">第10章 如何正确地进行抽象</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/10.html#_10-1-页面划分成模块" class="sidebar-link">10.1 页面划分成模块</a></li><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/10.html#_10-2-模块抽象成数据" class="sidebar-link">10.2 模块抽象成数据</a></li><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/10.html#_10-3-深入理解配置化" class="sidebar-link">10.3 深入理解配置化</a></li><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/10.html#_10-4-组件配置化" class="sidebar-link">10.4 组件配置化</a></li></ul></li><li><a href="/vue-ebook/vue-ebook/11.html" class="sidebar-link">第11章 全局数据管理与 Vuex</a></li><li><a href="/vue-ebook/vue-ebook/12.html" class="sidebar-link">第12章 实战：三天开发一个管理端</a></li><li><a href="/vue-ebook/vue-ebook/13.html" class="sidebar-link">第13章 实战：表单配置化实现</a></li><li><a href="/vue-ebook/vue-ebook/14.html" class="sidebar-link">第14章 实战：使用 Webpack 或 Vue CLI 搭建多页应用</a></li><li><a href="/vue-ebook/vue-ebook/15.html" class="sidebar-link">第15章 Vue 周边拓展</a></li><li><a href="/vue-ebook/vue-ebook/16.html" class="sidebar-link">第16章 关于 Vue 3.0</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>后记</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/99.html" class="sidebar-link">关于框架选型</a></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="第10章-如何正确地进行抽象"><a href="#第10章-如何正确地进行抽象" aria-hidden="true" class="header-anchor">#</a> 第10章 如何正确地进行抽象</h1> <p>关于抽象，它其实是一个通用的能力。而掌握了抽象的能力后，当你用到应用、页面中，不管是组件化、配置化还是数据流等处理，都可以水到渠成。</p> <p>对于写业务代码，很多前端都觉得枯燥无趣，且认为容易达到技术瓶颈。其实并不是这样的，几乎所有被我们称之为“技术需求”、“技术工具”的开发，它都来自于业务的需要，Vue 也是。而在前端领域，业务开发就真的只是调节样式、拼接模板、绑定事件、接口请求、更新页面这些内容吗？其实也不是的，在学习完本章之后，你会发现前端的世界也可以这么精彩，而 Vue 也可以这么好玩。</p> <p>我们下面将按照将页面划分成模块、模块抽象成数据、对应用进行配置化，以及组件的抽象、组件配置化的顺序，来探索这样一种新玩法吧。</p> <h2 id="_10-1-页面划分成模块"><a href="#_10-1-页面划分成模块" aria-hidden="true" class="header-anchor">#</a> 10.1 页面划分成模块</h2> <p>产品在设计一个页面的时候，会根据内容和功能的不同，设计出不同的模块，然后再拼凑成页面。对于前端同学来说，拿到一个设计好的交互稿或者设计图之后，需要进行逆向拆解，我们要把一个页面按照功能和内容划分出一个个的模块。而我们拆出来的模块并不一定完全跟产品设计的一致，会根据不同的粒度、视觉和易抽象程度来进行划分。</p> <h3 id="_10-1-1-什么是模块"><a href="#_10-1-1-什么是模块" aria-hidden="true" class="header-anchor">#</a> 10.1.1 什么是模块</h3> <p>我们来看看常见的应用页面，这里我截取了自己的博客来进行说明：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-10-1.jpg" alt="image"><br>
图 10-1 博客页面</p> <p>我们可以直观地根据视觉感受来划分下：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-10-2.jpg" alt="image"><br>
图 10-2 博客页面模块划分</p> <p>大致可以分为三大块：</p> <ul><li>头部：快速导航栏</li> <li>左侧：内容板块</li> <li>右侧：推广导航板块</li></ul> <p>其实论坛类、博客类的页面大多如此，我们再来看看用 Vuepress 搭建的前端游乐场（跟 Vue 官网很像）：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-10-3.jpg" alt="image"><br>
图 10-3 前端游乐场页面</p> <p>除此之外，还有视频类、电商类等各种角色的网站，大家有空也可以去看看，思考下里面是怎么划分的。或许你会觉得，想这些有什么用呢？这对我们平时的工作有什么帮助吗？其实<code>观察 -&gt; 思考 -&gt; 总结</code>也是有意思的事情，可以多一种角度来思考自己的工作内容，也能提高写代码的趣味性。如果你要认真地把这个过程放置到你的工作中，也可以找到很多提升工作效率的方法，也会让你的路越走越顺畅。</p> <p>模块的划分，其实最终在代码中呈现出来的，常常是组件的划分。</p> <h3 id="_10-1-2-组件与模块"><a href="#_10-1-2-组件与模块" aria-hidden="true" class="header-anchor">#</a> 10.1.2 组件与模块</h3> <p><a href="/vue-ebook/vue-ebook/4.html">《第4章 Vue 组件的使用》</a>中，我们详细地介绍了组件。虽然组件和模块是不一样的两个概念，但是模块有些时候也可以作为一个组件来维护，而模块也可以是属于某个组件、或是包含哪些组件的关系。模块更多是在是视觉上呈现的划分，而组件则更偏向功能上的划分。一个模块是否可以成为一个组件，需要看这个模块是否拥有属于自己的状态、数据、事件等对于组件的封装也都已经在 4.4 章节中有详细的描述。</p> <h2 id="_10-2-模块抽象成数据"><a href="#_10-2-模块抽象成数据" aria-hidden="true" class="header-anchor">#</a> 10.2 模块抽象成数据</h2> <p>想象一下，在把数据与逻辑分离到极致的时候，我们看一个应用/页面，会看到一具静态的逻辑躯壳，以及动态的数据组成。数据如灵魂般地注入到应用/页面中，可使其获得生命。关于如何进行数据的抽离，通常来说可以把变化的部分分离和抽象，然后通过注入的方式，来实现具体的功能和展示。</p> <p>是否有点抽象？这样的一个分离过程，也可以理解为我们写好的一个页面，需要从后台获取到数据，然后根据数据渲染出对应的内容。在这里，页面就是静态的，而获取的数据就是动态的。从另外一个角度来说，除了后台请求的数据，我们在 Vue 中通过<code>data</code>绑定的数据都可以抽离。关于这些可抽离的数据，我们来简单识别和划分一下。</p> <h3 id="_10-2-1-状态数据"><a href="#_10-2-1-状态数据" aria-hidden="true" class="header-anchor">#</a> 10.2.1 状态数据</h3> <p>在一个应用的设计里，我们可能会拥有多个组件，每个组件又各自维护着自己的某些状态，同时部分状态相互影响着，叠加起来呈现出应用最终的整体状态。这些状态，都可以通过数据的方式来表示，我们简单称之为<strong>状态数据</strong>。怎么定义状态数据？最浅显或是最直观的办法就是，这些数据可以直接影响页面的呈现，如对话框的出现、隐藏，标签的激活、失活，长流程中的进行中步骤等，都可以作为状态数据。在 Vue 里面，状态数据会经常与 <code>v-show</code>、<code>v-if</code>等逻辑结合使用。</p> <p>我们的应用，大多数都是呈现树状结构，一层层地往下分解，直到无法分割的某个简单功能。同时，我们的组件也会呈现出来这样树状的方式，状态是跟随着组件维护，某个功能状态属于组件自己，最外层的状态则属于整个应用，当然这个应用可以看做是一个组件。</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-10-9.jpg" alt="image"><br>
图 10-4 博客模块划分</p> <p>如图 10-4，图中的每个模块都可以附着着一个“是否可见”的状态。我们的应用状态整体上也是会呈现树状的方式，与我们的组件相对应，就像 DOM 节点树、CSS 规则树和渲染树的关系。</p> <h3 id="_10-2-2-动态数据"><a href="#_10-2-2-动态数据" aria-hidden="true" class="header-anchor">#</a> 10.2.2 动态数据</h3> <p>我们还有很多的数据，如内容、个人信息等，都是需要我们从数据库拉取回来的。这种需要动态获取然后用于展示或是影响展示的一些数据，我们可以称作动态数据。动态数据不同于状态数据，并不会跟随着应用的生命周期而改变，也不会随着应用的关闭而消失。它们独立存在于外界，通过注入的方式进入应用，并影响具体的展示和功能逻辑。</p> <p>和状态数据不一样，动态数据并不一定呈现为树状的形式。它可以是并行的，可以是联动关系，随着注入的地方不一样，最终在应用中形成的结构也会不一致。我们可以简单理解为每个动态数据都是平等的。</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-10-10.jpg" alt="image"><br>
图 10-5 文章列表</p> <p>如图 10-5，这里每篇文章内容，都是单独的一份从后台请求的数据注入。其实博客通常是静态模板，不存在从后台请求的情况，这里打个比喻，大家可以想象下社区里的文章、知乎帖子、微博等等。</p> <h3 id="_10-2-3-将数据与应用抽离"><a href="#_10-2-3-将数据与应用抽离" aria-hidden="true" class="header-anchor">#</a> 10.2.3 将数据与应用抽离</h3> <p>要怎么理解将数据与应用抽离呢？形象点形容，就像是我们一个公司，所有的桌子椅子装修和电脑都是静态的，它们相当于一个个的组件，同时每个办公室也可以是一个大点的组件或是模块。那么在我们这个公司里：</p> <ul><li>状态数据：椅子的位置、消耗的电量、办公室的照明和空调状态等</li> <li>动态数据：员工等各种人员流动</li></ul> <p>当然，公司里没有人员流动的时候，似乎就是个空壳。每天上班的时候，一个个的程序员来到公司里，给公司注入灵魂，公司得以运作。要说将数据和应用抽离，作用到这个例子中大概是这个样子的：</p> <div class="language-cmd extra-class"><pre class="language-text"><code># 将公司和人分开（下班后）
--------------------------------------------------------
                         公司
---------------------------  ---------------------------
|                                                      |  人           人
|                                                      |      人          人
|                         办公楼                        |           人
|                                                      |   人     人     人  人
|                                                      |   人      人   人
---------------------------  ---------------------------


# 在公司正常运作的时候
--------------------------------------------------------
                         公司
--------------------------------------------------------
|   人     人             人   人       人     人 人    |
|           人            人   人     人          人    |
|        人    人    办公楼   人   人          人       |
|     人    人                人  人     人     人  人  |
|     人     人         人      人     人      人   人  |
--------------------------------------------------------
</code></pre></div><p>当然，人不只是站在办公楼里面这么简单，更多的，人会与各种物件进行交互和反馈，人与人之间也会相互交流和影响。但是这样简单的管理，很容易造成公司的混乱，所以我们会把人员有规律有组织地分别隔离到每个办公室、隔间里面：</p> <div class="language-cmd extra-class"><pre class="language-text"><code># 按照组织进行分隔
--------------------------------------------------------
                         公司
--------------------------------------------------------
|   人   |  人   人  |         | 人    人    |  人 人    |
|   人   |     人    |         |    人  人   |   人  人  |
|--------    人  人  |  办公楼  |  人    人    --------- |
|     人 |  人       |         |  人     人  |   人  人  |
|     人 |   人   人 |         | 人     人   |  人   人  |
--------------------------------------------------------
</code></pre></div><p>这就是我们要做的，不只是如何划分数据、将数据与应用抽离，我们还需要将其有规律地管理。所以，这大概是接下来的要讲的内容。我们知道哪些数据需要抽离、如何将数据抽离出来，同时，我们还需要知道，这些数据在抽离出来之后，该怎么去进行管理。</p> <h3 id="_10-2-4-适度的管理"><a href="#_10-2-4-适度的管理" aria-hidden="true" class="header-anchor">#</a> 10.2.4 适度的管理</h3> <p>与组件的封装不适宜过度一样，数据的抽象、隔离、管理，也是需要适度的。当我们的应用很小，只有简单的功能的时候，我们甚至不需要对这些状态、数据什么的进行特殊的管理，甚至几个简单的变量就可以搞定了。随着应用组件数量变多，我们开始有了组件的作用域，当组件需要通信，我们可以通过简单的事件机制、或是共享对象的方式来进行交互。</p> <p>当我们的项目越做越大，要在上百的状态、上万的数据里要按照想要的方式去展示我们的应用，这时候一个状态管理工具则可以轻松解决乱糟糟的数据流问题。关于在 Vue 中怎样进行数据和状态管理的更多内容，会在 11 章讲述。</p> <h2 id="_10-3-深入理解配置化"><a href="#_10-3-深入理解配置化" aria-hidden="true" class="header-anchor">#</a> 10.3 深入理解配置化</h2> <p>配置化的思想，如今也不仅仅存在于前端或者是某个领域。所有的系统和架构设计，都可以用领域抽象、数据抽离、配置化等方式，搭建灵活配置、模块解耦的系统，前端也不例外。</p> <h3 id="_10-3-1-可配置的数据"><a href="#_10-3-1-可配置的数据" aria-hidden="true" class="header-anchor">#</a> 10.3.1 可配置的数据</h3> <p>数据的配置，或许大家会比较熟悉，我们很多的管理端都是用来进行数据配置的。而数据配置的最终效果，则包括影响展示端的页面内容、应用的状态控制等。例如文案、活动、功能展示，都可以通过数据配置进行控制。</p> <h4 id="应用中的可配置数据"><a href="#应用中的可配置数据" aria-hidden="true" class="header-anchor">#</a> 应用中的可配置数据</h4> <p>最常见的数据配置，大概是前面说过的一些内容配置，文案、说明等，为此还产生了运营这样的职位。常见的运作方式，是搭起一整套的运营管理平台，除了一些简单的文字或是数据以外，广告内容、推荐位等，都可以通过平台进行配置。</p> <h4 id="代码中的可配置数据"><a href="#代码中的可配置数据" aria-hidden="true" class="header-anchor">#</a> 代码中的可配置数据</h4> <p>有些时候，我们也会在代码里面抽象出一些可配置的数据。例如，这个需求产品要求查询一周的数据，我们在开发的时候并不会将 7 天写死在涉及计算的每行代码中，而是将天数配置为 7 天，设置成全局变量：</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">const</span> <span class="token constant">QUERY_DAY_NUM</span> <span class="token operator">=</span> <span class="token number">7</span><span class="token punctuation">;</span>
</code></pre></div><p>这样，当需要在紧急情况支持其他天数（五一、国庆、过年等假期）的时候，我们就可以只需要改动这里就可以了。更方便的情况是，这个数据的配置可以放在管理端，通过管理端下发到后台，前端展示的时候只需要从后台获取具体的天数就可以了。</p> <h4 id="文件里的可配置数据"><a href="#文件里的可配置数据" aria-hidden="true" class="header-anchor">#</a> 文件里的可配置数据</h4> <p>虽然我们可配置的数据单独抽出来维护，但常常是将这个配置也直接写到代码里。那么如果我们需要调整这些配置，调整后还需要重新打包部署，这种情况开销大、效率低。所以在一些时候，我们会把这样的可配置数据，单独写到某个文件里维护，这个文件不合我们的代码打包到一起。当需要调整的时候，只需要单独下发一个配置文件就好了。</p> <h3 id="_10-3-2-可配置的接口"><a href="#_10-3-2-可配置的接口" aria-hidden="true" class="header-anchor">#</a> 10.3.2 可配置的接口</h3> <p>关于接口的配置化，目前来说见过的不是特别多。毕竟现实场景中，我们的很多数据和接口并不是简单的增删查改这样的功能，很多时候还需要在接口返回前后，做一系列的逻辑处理。简单地说，很多的业务接口场景复用性不高，前后端除去协议、基础规范的定义之后，很少再能进行更深层次的抽象，导致接口配置化的改造成本较大。</p> <p>配置化的实现有两点很重要的东西：<strong>规范</strong>和<strong>解决方案</strong>。如果说目前较好的从前端到后台的规范，可能是 GraphQL 和 Restful 了，大家不熟悉的也可以去看看。当然，或许有些团队已经实现了，也希望能看到一些相关的解决方案。</p> <h3 id="_10-3-3-可配置的页面"><a href="#_10-3-3-可配置的页面" aria-hidden="true" class="header-anchor">#</a> 10.3.3 可配置的页面</h3> <p>页面的配置化，可能也已经不少见了。像我刚出道的时候，也写过一个拖拽的 Demo（如图 10-6），当时自己实现完，信心倍增。大概每个前端的成长过程中，都会伴随着一个管理端配置化的需求吧。</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/dd_custom_pages.png" alt="image"><br>
图 10-6 拖拽生成 H5 的 Demo</p> <p>有些时候，一些页面比较简单，里面的板块、功能比较相似，可能文案不一致、模块位置调整了、颜色改变等等。虽然说复制粘贴再改一改，很多时候也能满足要求，但是我们通过抽象和配置化，就可以把重复性的工作交给机器，省下来的精力可以做更多富有创造性的工作。这种页面的配置，基本上有两种实现方式：<br>
(1) 配置后生成静态页面的代码，直接加载生成的页面代码。<br>
(2) 写通用的配置化逻辑，在加载页面的时候拉取配置数据，动态生成页面。</p> <p>基于 SEO 和实现复杂度各种情况，第一种方式大概是目前比较常用的，第二种的实现难度会稍微大一些。第一种方式，很多适用于一些移动端的模版页面开发，例如简单的活动页面、商城页面等等。第二种的话，更多的是一些管理平台的实现，毕竟大多数都是增删查改，形式无非列表、表单和菜单等。配置化的核心大概是场景分析和功能拆解，所以抛开使用场景来做一个所谓“通用”的配置化是不现实的。但是如果把问题范围局限在解决特定的场景，就可以做出合适的配置化功能。</p> <h2 id="_10-4-组件配置化"><a href="#_10-4-组件配置化" aria-hidden="true" class="header-anchor">#</a> 10.4 组件配置化</h2> <p>这里我们来讲一下简单的配置化组件的实现，关于组件的封装前面我们也讲过了。下面的组件配置化实现说明，我们拿这样一个卡片组件来作为例子：</p> <p><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-10-16.jpg" alt="image"><br>
图 10-7 卡片组件样式</p> <h3 id="_10-4-1-可配置的数据"><a href="#_10-4-1-可配置的数据" aria-hidden="true" class="header-anchor">#</a> 10.4.1 可配置的数据</h3> <p>首先是数据的配置，这大概是最基础的。当我们在封装组件的时候，很多数据都是通过作用域内的变量来动态绑定的，例如 Vue 里面则是通过<code>data</code>、<code>props</code>、<code>computed</code>等实例属性来维护 scope 内的数据绑定。作为一个卡片，内容是从外面注入的，所以我们这里使用<code>props</code>来获取：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>template</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span>{{cardInfo.question}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">v-if</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>cardInfo.withImage<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">:url</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>cardInfo.imageUrl<span class="token punctuation">&quot;</span></span> <span class="token punctuation">/&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>{{cardInfo.content}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>likeIt()<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>点赞<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>keepIt()<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>收藏<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>comment in cardInfo.comments<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>{{comment}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>template</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
  <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
    name<span class="token punctuation">:</span> <span class="token string">&quot;my-card&quot;</span><span class="token punctuation">,</span>
    props<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token comment">// 传入数据</span>
      cardInfo<span class="token punctuation">:</span> <span class="token punctuation">{</span>
        type<span class="token punctuation">:</span> Object<span class="token punctuation">,</span>
        <span class="token function-variable function">default</span><span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span>
        isContextShown<span class="token punctuation">:</span> <span class="token boolean">false</span>
      <span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    methods<span class="token punctuation">:</span> <span class="token punctuation">{</span>
      <span class="token function">likeIt</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token function">keepIt</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token function">mounted</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>上面只简单地实现部分的卡片内容，我们在使用的时候，只需要将数据传入到这个组件中就可以了：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>my-card</span> <span class="token attr-name">:cardInfo</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>cardInfo<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>my-card</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>在这里，<code>cardInfo</code>就是我们用来配置卡片内容的数据，我们可以从后台拉取了所有卡片的列表信息，然后配合<code>v-for</code>来绑定和生成每一个卡片内容。</p> <h3 id="_10-4-2-可配置的样式"><a href="#_10-4-2-可配置的样式" aria-hidden="true" class="header-anchor">#</a> 10.4.2 可配置的样式</h3> <p>样式的配置，通常是通过<code>class</code>来实现的。其实这更多地是对 CSS 进行配置化设计，与我们的 HTML 和 Javascript 关系则比较少。样式的配置，需要我们考虑 CSS 的设计，通常来说我们有两种方式：<br>
(1) 根据子元素匹配，来描述 CSS。<br>
(2) 根据子 class 匹配，来描述 CSS。</p> <h4 id="根据子元素配置-css"><a href="#根据子元素配置-css" aria-hidden="true" class="header-anchor">#</a> 根据子元素配置 CSS</h4> <p>这是以前比较常用的一种方式，简单地说，就是通过 CSS 匹配规则中的父子元素匹配，来完成我们的样式设计。例如，我们有个模块：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>my-dialog<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>header</span><span class="token punctuation">&gt;</span></span>I am header.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>header</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span><span class="token punctuation">&gt;</span></span>
    blablablabla...
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>footer</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span><span class="token punctuation">&gt;</span></span>Submit<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>footer</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>样式则会这样设计：</p> <div class="language-CSS extra-class"><pre class="language-css"><code><span class="token selector">.my-dialog</span> <span class="token punctuation">{</span>
  <span class="token property">background</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token selector">.my-dialog &gt; header</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token selector">.my-dialog &gt; section</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token selector">.my-dialog &gt; footer</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre></div><p>或者说用 LESS 或是 SASS：</p> <div class="language-LESS extra-class"><pre class="language-less"><code><span class="token selector">.my-dialog</span> <span class="token punctuation">{</span>
  <span class="token property">background</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
  <span class="token selector">&gt; header</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token selector">&gt; section</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token selector">&gt; footer</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>通过这种方式设计，或许我们在写代码的时候会稍微方便些，但是在维护上面很容易踩坑。只需要调整一次页面的 DOM 结构，就可以让你改 CSS 改到崩溃。</p> <h4 id="根据子-class-配置-css"><a href="#根据子-class-配置-css" aria-hidden="true" class="header-anchor">#</a> 根据子 class 配置 CSS</h4> <p>其实相对于匹配简单的父子和后代元素关系，使用 class 来辅助匹配，可以解决 DOM 调整的时候带来的问题。这里我们使用 BEM 作为例子来解释下大概的想法吧。BEM 的意思就是块（block）、元素（element）、修饰符（modifier），是一种前端命名方法论。大家感兴趣可以去搜一下。简单说，我们写 CSS 的时候就是这样的：</p> <div class="language-CSS extra-class"><pre class="language-css"><code><span class="token selector">.block</span><span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token selector">.block__element</span><span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token selector">.block--modifier</span><span class="token punctuation">{</span><span class="token punctuation">}</span>
</code></pre></div><p>表 10-1 BEM 命名规范</p> <table><thead><tr><th>命名</th> <th>说明</th> <th>举例</th></tr></thead> <tbody><tr><td>B-block</td> <td>块<br>可以与组件和模块对应的命名</td> <td>如 card、dialog 等</td></tr> <tr><td>E-element</td> <td>元素</td> <td>如 header、footer 等</td></tr> <tr><td>M-modifier</td> <td>修饰符<br>可视作状态等描述</td> <td>如 actived、closed 等</td></tr></tbody></table> <p>这样的话，我们上述的代码则会变成：</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>my-dialog<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>header</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>my-dialog__header<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>I am header.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>header</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>my-dialog__section<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    blablablabla...
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>footer</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>my-dialog__footer<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>my-dialog__btn--inactived<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Submit<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>footer</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>搭配 LESS 的话，其实样式还是挺容易写的：</p> <div class="language-LESS extra-class"><pre class="language-less"><code><span class="token selector">.my-dialog</span> <span class="token punctuation">{</span>
  <span class="token property">background</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
  <span class="token selector">&amp;__header</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token selector">&amp;__section</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token selector">&amp;__footer</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
  <span class="token selector">&amp;__btn</span> <span class="token punctuation">{</span>
    &amp;<span class="token operator">-</span><span class="token operator">-</span>inactived
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>其实大家看了下，就发现这样的弊端了。我们在写 HTML 的时候，需要耗费很多的时间来写这些 class 名字。更麻烦的的是，当我们需要切换某个元素状态的时候，判断条件会变得很长，像：</p> <div class="language-HTML extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">:class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>isActived ? 'my-dialog__btn--actived' : 'my-dialog__btn--inactived'<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Submit<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>这样写太长了，维护性上、可读性上都不大友好。当然我们还可以这样使用：</p> <div class="language-HTML extra-class"><pre class="language-html"><code><span class="token comment">&lt;!-- 自己拼 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">:class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span><span class="token punctuation">'</span>my-dialog__btn--' + (isActived ? 'actived' : 'inactived')<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Submit<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
<span class="token comment">&lt;!-- 也可以把修饰符部分脱离 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>my-dialog__btn<span class="token punctuation">&quot;</span></span> <span class="token attr-name">:class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>isActived ? 'actived' : 'inactived'<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>Submit<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>这样会稍微好一些。BEM 的优势和弊端也都是很明显的，大家也可以根据具体的团队规模、项目规模、使用场景等，来决定要怎么设计。当然，如今很多框架都支持样式的作用域，通常是通过在 class 里添加随机 MD5 等，来保持局部作用域的 class 样式，或者也可以使用 Shawdow DOM 来进行隔离。</p> <h3 id="_10-4-3-可配置的状态和展示"><a href="#_10-4-3-可配置的状态和展示" aria-hidden="true" class="header-anchor">#</a> 10.4.3 可配置的状态和展示</h3> <p>可配置的状态和展示，更多时候是指某些模块的状态、展示的效果又是如何等。例如，我们需要一个对话框，其头部、正文文字、底部按钮等功能都可支持配置：</p> <div class="language-HTML extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>my-dialog<span class="token punctuation">&quot;</span></span> <span class="token attr-name">:class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>{'show': isShown}<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>header</span> <span class="token attr-name">v-if</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>cardInfo.title<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>{{cardInfo.title}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>header</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>section</span> <span class="token attr-name">v-if</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>cardInfo.content<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>{{cardInfo.content}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>section</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>footer</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">v-for</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">&quot;</span>button in cardInfo.buttons<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>{{button.text}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>footer</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><p>我们可以通过<code>cardInfo.title</code>来控制是否展示头部，可以通过<code>cardInfo.buttons</code>来控制底部按钮的数量和文字。这只是最简单的实例，我们可以通过配置，来控制出完全不一样的展示效果。搭配样式的配置，更是能让组件出神入化。当然，很多时候我们组件的封装是需要与业务设计相关，这样维护性能也会稍微好一些，这些前面也都有说到过。</p> <h3 id="_10-4-4-可配置的功能"><a href="#_10-4-4-可配置的功能" aria-hidden="true" class="header-anchor">#</a> 10.4.4 可配置的功能</h3> <p>功能的配置，其实很多也与状态和展示的配置相关。但是我们有些与业务相关的功能，则可以结合展示、功能来定义这样的配置。</p> <p>举个例子，我们的这个卡片可以是视频、图片、文字三者其中之一的卡片：</p> <ul><li>视频：点击播放</li> <li>图片：点击新窗口查看</li> <li>文字：点击无效果</li></ul> <p>这种时候，我们可以两种方式：<br>
(1) 每个功能模块自己控制，同时通过配置控制哪个功能模块的展示。<br>
(2) 模块展示会有些耦合，但在点击事件里，根据配置来进行不同的事件处理，获取不同的效果。</p> <p>对应维护性和可读性来说，第一种方式会获得更好的效果。如果问什么情况下会用到第二种，大概是同样的呈现效果，在不同场景下的逻辑功能不一样时，使用会比较方便。</p> <p>功能配置化这块就不过多描述了，毕竟这块需要与业务场景密切结合，后面<a href="/vue-ebook/vue-ebook/13.html">《第13章 实战：表单配置化实现》</a>也有介绍。大家更多地可以思考下，自己的项目中，是否可以有调整的空间，来使得整体的项目更好维护呢？</p></div> <!----> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/godbasin/vue-ebook/edit/ebook-sourcecode/docs/vue-ebook/10.md" target="_blank" rel="noopener noreferrer">帮阿猪改善此页面！</a> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></div> <!----> <div style="margin-top:30px;"><div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-sm-0 el-col-md-2 el-col-lg-4" style="padding-left:10px;padding-right:10px;display:block;"><div style="width:1px;height:1px;"></div></div> <div class="el-col el-col-24 el-col-sm-24 el-col-md-18 el-col-lg-16" style="padding-left:10px;padding-right:10px;"><div class="el-card box-card is-always-shadow"><div class="el-card__header"><div class="clearfix"><span>温馨提示喵</span></div></div><div class="el-card__body"> <div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="el-image"><div class="image-slot"><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/loading.gif" style="width:100%;"></div><!----></div></div> <div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="copyright-text"><div>本书采用“保持署名—非商用”<a href="http://creativecommons.org/licenses/by-nc/4.0/" target="_blank">创意共享4.0许可证</a>。只要保持原作者署名和非商用，您可以自由地阅读、分享、修改本书。</div> <div>作者：<a href="https://github.com/godbasin" target="_blank">被删</a></div></div></div></div></div></div></div></div></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/vue-ebook/vue-ebook/9.html" class="prev">
          第9章 思维转变与大型项目管理
        </a></span> <span class="next"><a href="/vue-ebook/vue-ebook/11.html">
          第11章 全局数据管理与 Vuex
        </a>
        →
      </span></p></div>  <div class="gitalk-container theme-default-content"><div id="gitalk-container" class="content"></div></div></main> <div id="kitty-container"><span><div role="tooltip" id="el-popover-526" aria-hidden="true" class="el-popover el-popper" style="width:undefinedpx;display:none;"><!----><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/2code2.jpg" class="image"> <div class="text">牡羊猪的猫粮罐</div> </div><div id="kitty" style="background:url(https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/kitty2.svg);"></div></span> <div class="el-dialog__wrapper" style="display:none;"><div role="dialog" aria-modal="true" aria-label="牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）" class="el-dialog" style="margin-top:15vh;"><div class="el-dialog__header"><span class="el-dialog__title">牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）</span><button type="button" aria-label="Close" class="el-dialog__headerbtn"><i class="el-dialog__close el-icon el-icon-close"></i></button></div><!----><!----></div></div></div></div><div class="global-ui"></div></div>
    <script src="/vue-ebook/assets/js/app.0a4e61a5.js" defer></script><script src="/vue-ebook/assets/js/3.846561a8.js" defer></script><script src="/vue-ebook/assets/js/2.eed49fdd.js" defer></script><script src="/vue-ebook/assets/js/9.748381e0.js" defer></script>
  </body>
</html>
